package cz.proks.easyhelpdesk.gae.api.impl.db;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import cz.proks.easyhelpdesk.api.ThreadApi;
import cz.proks.easyhelpdesk.api.config.Configuration;
import cz.proks.easyhelpdesk.api.exception.ApiException;
import cz.proks.easyhelpdesk.api.model.Thread;
import cz.proks.easyhelpdesk.gae.api.impl.dbo.ThreadMember;
import cz.proks.easyhelpdesk.gae.api.impl.dbo.Ticket;

@Repository(Configuration.DB.THREAD_API)
@Scope("prototype")
public class ThreadApiImpl extends BaseApiImpl<Thread> implements ThreadApi {    
    private final Logger log = LoggerFactory.getLogger(getClass());
        
    @Override
    protected Class<Thread> getDomainClass() {
        return Thread.class;
    }

    @Override
    protected Thread getDboObject(Thread entity) {
        cz.proks.easyhelpdesk.gae.api.impl.dbo.Thread dbo = instantiateDbo(entity);
        
        if (dbo != null)
            dbo.toDbo(entity);
        
        return dbo;
    }
    
    @Override
    @Transactional(readOnly = false)
    public void addTicket(Long id, Long ticketId) throws ApiException {
        log.debug("addTicket():: Start with id '{}', ticketId '{}'", id, ticketId);
        
        Thread thread = get(id);
        
        Ticket ticket = new Ticket();
        ticket.setId(ticketId);
        
        if (ticketExits(ticket, thread.getTickets()))
            return;
        
        if (thread.getEntryTicketId() == null)
            thread.setEntryTicketId(ticketId);
        
        thread.getTickets().add(ticket);
        
        update(thread);
        
        log.debug("addTicket():: Exit");
    }

    @Override
    @Transactional(readOnly = false)
    public void removeTicket(Long id, Long ticketId) throws ApiException {
        log.debug("removeTicket():: Start with id '{}', ticketId '{}'", id, ticketId);
        
        Thread thread = get(id);
        
        Ticket ticket = new Ticket();
        ticket.setId(ticketId);
        
        if (!ticketExits(ticket, thread.getTickets()))
            return;
        
        thread.getTickets().remove(ticket);
        
        if (thread.getTickets().isEmpty())
            remove(thread.getId());
        else
            update(thread);
        
        log.debug("removeTicket():: Exit");
    }       
    
    @Override
    @Transactional(readOnly = true)
    public List<Thread> listForHelpdeskMemberWithPaging(Long helpdeskMemberId, Long from, Long to) throws ApiException {
        log.debug("listForHelpdeskForPaging():: Start with helpdeskMemberId '{}', from '{}', to '{}'", new Object[] {helpdeskMemberId, from, to});
        
        EntityManager entityManager = getEntityManager();
        
        Query queryTM = entityManager.createNamedQuery("ThreadMember.listForHelpdeskMember");
        queryTM.setParameter("helpdeskMemberId", helpdeskMemberId);
        List<ThreadMember> dboThreadMembers = queryTM.getResultList();
        
        List<Long> threadIds = new LinkedList<Long>();
        if (dboThreadMembers != null)
            for (ThreadMember dboThreadMember : dboThreadMembers) 
                threadIds.add(dboThreadMember.getThreadId());
        
        Query query = entityManager.createNamedQuery("Thread.listForHeldpeskMemberWithPaging");
        query.setParameter("threadIds", threadIds);
        query.setFirstResult((int) (to - from + 1));
        query.setMaxResults(to.intValue());
        
        List<Thread> entities = new LinkedList<Thread>();
        
        if (!threadIds.isEmpty())
            try {
                List<cz.proks.easyhelpdesk.gae.api.impl.dbo.Thread> dboList = query.getResultList();
                entities.addAll(fromDboList(dboList));
            } catch (EmptyResultDataAccessException e) {
                // NOP
            }
        
        log.debug("listForHelpdeskForPaging():: End with {}", (entities == null ? "null list" : "list of " + entities.size() + " elements"));
        return entities;
    }       
    
    private <T extends cz.proks.easyhelpdesk.api.model.Ticket> boolean  ticketExits(T ticket, Collection<T> tickets) {
        return tickets != null ? tickets.contains(tickets) : false;
    }
}
